package com.yifeng.repo.micro.service.server.engine.configure;

import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.gomcarter.frameworks.base.common.AssertUtils;
import com.yifeng.base.account.api.AdmOrgMasterDataRestService;
import com.yifeng.base.account.api.OpsOrgMasterDataRestService;
import com.yifeng.base.account.api.UserMasterDataRestService;
import com.yifeng.base.bds.api.store.StoreMasterDataRestService;
import com.yifeng.repo.base.mdm.MasterDataManager;
import com.yifeng.repo.base.mdm.console.impl.AdmOrgMasterDataRestServiceImpl;
import com.yifeng.repo.base.mdm.console.impl.OpsOrgMasterDataRestServiceImpl;
import com.yifeng.repo.base.mdm.console.impl.StoreMasterDataRestServiceImpl;
import com.yifeng.repo.base.mdm.console.impl.UserMasterDataRestServiceImpl;
import com.yifeng.repo.base.mdm.full.listener.FullDataListener;
import com.yifeng.repo.base.mdm.full.worker.FullDataWorker;
import com.yifeng.repo.base.mdm.loader.annotation.MdmCache;
import com.yifeng.repo.base.mdm.loader.aop.MdmCacheAnnotationAdvisor;
import com.yifeng.repo.base.mdm.loader.aop.MdmCacheAnnotationInterceptor;
import com.yifeng.repo.base.service.BaseServiceManager;
import com.yifeng.repo.base.utils.redis.client.JedisClient;
import com.yifeng.repo.base.utils.redis.worker.RedisCacheWorker;
import com.yifeng.repo.base.utils.redis.worker.RedisGeoWorker;
import com.yifeng.repo.base.utils.redis.worker.RedisLockWorker;
import com.yifeng.repo.micro.service.server.engine.master.idx.ServerEngineIdentifierGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.Advisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

/**
 * Created by daibing on 2024/2/27.
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(ServerEngineMasterProperties.class)
@ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX, name = "enabled", matchIfMissing = true)
public class ServerEngineMasterConfiguration {

    @Value("${spring.application.name}")
    private String applicationName;

    @Resource
    private ServerEngineMasterProperties masterProperties;

    @PostConstruct
    public void init() {
        this.checkAndUpdateProperties();
    }

    @Bean(initMethod = "init", destroyMethod = "destroy")
    @ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX, name = "enable-redis")
    public JedisClient jedisClient() {
        JedisClient jedisClient = new JedisClient();
        jedisClient.setUri(masterProperties.getBizCacheParam().getJedisUri());
        jedisClient.setMaxTotal(masterProperties.getBizCacheParam().getJedisMaxTotal());
        jedisClient.setMaxIdle(masterProperties.getBizCacheParam().getJedisMaxIdle());
        jedisClient.setMinIdle(masterProperties.getBizCacheParam().getJedisMinIdle());
        jedisClient.setBlockWhenExhausted(masterProperties.getBizCacheParam().isJedisBlockWhenExhausted());
        jedisClient.setMaxWaitMillis(masterProperties.getBizCacheParam().getJedisMaxWaitMillis());
        jedisClient.setTestOnBorrow(masterProperties.getBizCacheParam().isJedisTestOnBorrow());
        return jedisClient;
    }

    @Bean
    @ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX, name = "enable-redis")
    public RedisCacheWorker redisCacheWorker(JedisClient jedisClient) {
        return new RedisCacheWorker(jedisClient);
    }

    @Bean
    @ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX, name = "enable-redis")
    public RedisLockWorker redisLockWorker(JedisClient jedisClient) {
        return new RedisLockWorker(jedisClient);
    }

    @Bean
    @ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX, name = "enable-geo-by-redis")
    public RedisGeoWorker redisGeoWorker(JedisClient jedisClient) {
        return new RedisGeoWorker(jedisClient);
    }

    @Bean
    @ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX, name = "enable-worker-id-by-redis")
    public IdentifierGenerator identifierGenerator(RedisLockWorker redisLockWorker) {
        return new ServerEngineIdentifierGenerator(applicationName, redisLockWorker);
    }

    @Bean
    @ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX, name = "enable-account-mdm")
    public UserMasterDataRestService userMasterDataRestService() {
        return new UserMasterDataRestServiceImpl(masterProperties.getAccountConsoleParam());
    }

    @Bean
    @ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX, name = "enable-account-mdm")
    public AdmOrgMasterDataRestService admOrgMasterDataRestService() {
        return new AdmOrgMasterDataRestServiceImpl(masterProperties.getAccountConsoleParam());
    }

    @Bean
    @ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX, name = "enable-account-mdm")
    public OpsOrgMasterDataRestService opsOrgMasterDataRestService() {
        return new OpsOrgMasterDataRestServiceImpl(masterProperties.getAccountConsoleParam());
    }

    @Bean
    @ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX, name = "enable-bds-mdm")
    public StoreMasterDataRestService storeMasterDataRestService() {
        return new StoreMasterDataRestServiceImpl(masterProperties.getBdsConsoleParam());
    }

    @Bean
    @ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX, name = "enable-bds-mdm")
    public MasterDataManager masterDataManager(@Autowired(required = false) UserMasterDataRestService userMasterDataRestService,
                                               @Autowired(required = false) AdmOrgMasterDataRestService admOrgMasterDataRestService,
                                               @Autowired(required = false) OpsOrgMasterDataRestService opsOrgMasterDataRestService,
                                               @Autowired(required = false) StoreMasterDataRestService storeMasterDataRestService) {
        return new MasterDataManager(userMasterDataRestService, admOrgMasterDataRestService,
                opsOrgMasterDataRestService, storeMasterDataRestService);
    }

    @Bean(initMethod = "init", destroyMethod = "destroy")
    @ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX, name = "enable-mdm-full-data")
    public FullDataWorker fullDataWorker(MasterDataManager masterDataManager, @Autowired(required = false) FullDataListener fullDataListener) {
        return new FullDataWorker(masterDataManager, fullDataListener);
    }

    @Bean
    @ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX, name = "enable-base-service")
    public BaseServiceManager baseServiceManager() {
        return new BaseServiceManager(
                masterProperties.getBdsConsoleParam(),
                masterProperties.getMcsConsoleParam(),
                masterProperties.getMqttConsoleParam());
    }

    @Bean
    @ConditionalOnProperty(prefix = ServerEngineMasterProperties.PREFIX + ".mdm-aop-properties", name = "enabled")
    public Advisor mdmAopCacheAdvisor() {
        AssertUtils.notNull(masterProperties.getMdmAopProperties().getMdmCacheParams(), "启用主数据AOP缓存就必须设置缓存配置参数！");
        MdmCacheAnnotationInterceptor interceptor = new MdmCacheAnnotationInterceptor(masterProperties.getMdmAopProperties().getMdmCacheParams());
        MdmCacheAnnotationAdvisor advisor = new MdmCacheAnnotationAdvisor(interceptor, MdmCache.class);
        advisor.setOrder(masterProperties.getMdmAopProperties().getOrder());
        return advisor;
    }

    private void checkAndUpdateProperties() {
        if (masterProperties.getBizCacheParam() != null && masterProperties.getBizCacheParam().getRedisKeyPrefix() == null) {
            masterProperties.getBizCacheParam().setRedisKeyPrefix(applicationName);
        }
        if (masterProperties.getAccountConsoleParam() != null && masterProperties.getAccountConsoleParam().getAppId() == null) {
            masterProperties.getAccountConsoleParam().setAppId(applicationName);
        }
        if (masterProperties.getBdsConsoleParam() != null && masterProperties.getBdsConsoleParam().getAppId() == null) {
            masterProperties.getBdsConsoleParam().setAppId(applicationName);
        }
        if (masterProperties.getCustomerConsoleParam() != null && masterProperties.getCustomerConsoleParam().getAppId() == null) {
            masterProperties.getCustomerConsoleParam().setAppId(applicationName);
        }
        if (masterProperties.getSupplyConsoleParam() != null && masterProperties.getSupplyConsoleParam().getAppId() == null) {
            masterProperties.getSupplyConsoleParam().setAppId(applicationName);
        }
        if (masterProperties.getMcsConsoleParam() != null && masterProperties.getMcsConsoleParam().getAppId() == null) {
            masterProperties.getMcsConsoleParam().setAppId(applicationName);
        }
        if (masterProperties.getMqttConsoleParam() != null && masterProperties.getMqttConsoleParam().getAppId() == null) {
            masterProperties.getMqttConsoleParam().setAppId(applicationName);
        }
    }

}
